
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "global_var.h"
#include "../contrib/murmur3/murmur3.h"
#include "../contrib/base64/base64.h"

#include "mail_fmt.h"

/**
 * @brief init mail_store_t object
 *
 * @param ms if pass NULL, then malloc a new space
 * @return mail_store_t* rememeber to free if ms is NULL
 */
mail_store_t *init_mail_store(mail_store_t *ms)
{
	// mail_store_t *ms;
	if (ms == NULL)
		ms = malloc(sizeof(mail_store_t));
	memset(ms, 0, sizeof(mail_store_t));
	ms->data = NULL;

	return ms;
}

void destory_mail_store(mail_store_t *mail_store)
{
	if (mail_store != NULL)
	{
		if (mail_store->data != NULL)
		{
			free(mail_store->data);
			mail_store->data = NULL;
		}
		free(mail_store);
	}
}

/**
 * @brief
 *
 * @example Tue,  2 Aug 2022 03:29:37 +0000 (UTC)
 * @param rs (out)
 * @param max_len must >= 48
 * @return char* return NULL error, rs[0]='\0'
 */
char *rfc822_date_time(time_t t, char *rs, size_t max_len)
{
	if (max_len < 48)
	{
		rs[0] = '\0';
		return NULL;
	}
	const char weekl[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
	const char monthl[12][4] = {"Jan", "Feb", "Mar", "Apr ", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
	struct tm lt;
	localtime_r(&t, &lt);
	strftime(rs, max_len, "   , %e     %Y %T %z (%Z)", &lt);
	strncpy(rs, weekl[lt.tm_wday], 3);
	strncpy(rs + 8, monthl[lt.tm_mon], 3);

	return rs;
}

/**
 * @brief generate mail id,
 * using time, mail_store recv_time, ip, hostname and random
 * @param mail_store
 * @param r output, include terminal zero
 * @param max_len MUST>=40
 * @return unsigned char* r, =NULL error
 */
unsigned char *gen_mail_id(mail_store_t *mail_store, unsigned char *r, int max_len)
{
	if (max_len < 40) // 14 + 1 + 24 + 1
	{
		r[0] = '\0';
		return NULL;
	}

	unsigned char buf[512] = {0};
	memcpy(buf, &(mail_store->recv_time), sizeof(time_t));
	memcpy(buf + sizeof(time_t), mail_store->ip, strlen(mail_store->ip));
	memcpy(buf + sizeof(time_t) + strlen(mail_store->ip), mail_store->hostname, strlen(mail_store->hostname));
	int rdm = rand();
	memcpy(buf + sizeof(time_t) + strlen(mail_store->ip) + strlen(mail_store->hostname), &rdm, sizeof(int));

	unsigned char mmh3[16] = {0};
	if (__WORDSIZE == 64)
		MurmurHash3_x64_128(buf, sizeof(time_t) + strlen(mail_store->ip) + strlen(mail_store->hostname) + sizeof(int), (unsigned int)rdm, mmh3);
	else
		MurmurHash3_x86_128(buf, sizeof(time_t) + strlen(mail_store->ip) + strlen(mail_store->hostname) + sizeof(int), (unsigned int)rdm, mmh3);

	time_t t = time(NULL);
	struct tm lt;
	localtime_r(&t, &lt);
	strftime(r, max_len, "%Y%m%d%H%M%S.", &lt);

	base64_encode(mmh3, 16, r + 15, max_len - 15);

	return r;
}

/**
 * @brief
 * Return-path-line  = "Return-Path:" FWS Reverse-path <CRLF>
 * @param mailfrom or Reverse-path, must have terminating '\0'
 * @return unsigned char*
 */
unsigned char *gen_return_path_line(unsigned char *mailfrom)
{
	short l = strlen(mailfrom);
	unsigned char *rp = (unsigned char *)malloc(sizeof(unsigned char) * (13 + l + 2 + 1));
	strcpy(rp, "Return-Path: ");
	strcpy(rp + 13, mailfrom);
	strcpy(rp + 13 + l, "\r\n");

	return rp;
}

/**
 * @brief
 * @example from mail-lf1-x131.google.com (mail-lf1-x131.google.com [IPv6:2a00:1450:4864:20::131])
 * by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 693BC2127B
 * for <linux-doc@vger.kernel.org>; Mon,  1 Aug 2022 20:29:30 -0700 (PDT)
 * @return unsigned char*
 */
unsigned char *gen_received_line(mail_store_t *mail_store, unsigned char *rs, size_t max_len)
{
	unsigned char lnameldomain[256];
	if (strlen(g_hostname) == 0 && strlen(g_hostdomain) == 0)
		strcpy(lnameldomain, "local");
	else if (strlen(g_hostname) == 0)
		strcpy(lnameldomain, g_hostdomain);
	else if (strlen(g_hostdomain) == 0)
		strcpy(lnameldomain, g_hostname);
	else
		snprintf(lnameldomain, 256, "%s.%s", g_hostname, g_hostdomain);

	unsigned char dt[48];
	rfc822_date_time(mail_store->recv_time, dt, 48);

	snprintf(rs, max_len, "Received: from %s ([%s]) by %s id %s; %s", mail_store->hostname, mail_store->ip, lnameldomain, mail_store->id, dt);

	return rs;
}
